﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Objects;
using System.Linq;
using System.Web;
using System.Web.Caching;
using VietTrips.Domain.Contexts;
using VietTrips.Domain.Helpers;
using VietTrips.Domain.Interfaces;
using VietTrips.Domain.Models;
using VietTrips.Domain.Repositories;

namespace VietTrips.Domain.Services
{
    public partial class UserManagerService
    {
        private readonly IUserRepository _userRepository = new UserRepository();

        #region Query Ordered By Sth

        private IQueryable<UserProfile> QueryUsersInOrdered(string orderedBy = "Username",
            IQueryable<UserProfile> input = null)
        {
            if (input == null)
            {
                input = CacheProvider.Get("QueryUsers", DateTime.Now.AddDays(1), () => _userRepository.All.AsNoTracking());
            }
            switch (orderedBy)
            {
                case "Email":
                     return input.OrderBy(profile => profile.Email).AsQueryable();
                case "Fullname":
                     return input.OrderBy(profile => profile.FullName).AsQueryable();
                case "Date":
                     return input.OrderBy(profile => profile.CreatedDate).AsQueryable();
                case "Username_desc":
                     return input.OrderByDescending(profile => profile.UserName).AsQueryable();
                case "Fullname_desc":
                     return input.OrderByDescending(profile => profile.FullName).AsQueryable();
                case "Email_desc":
                     return input.OrderByDescending(profile => profile.Email).AsQueryable();
                case "Date_desc":
                     return input.OrderByDescending(profile => profile.CreatedDate).AsQueryable();
                default:
                     return input.OrderBy(profile => profile.UserName).AsQueryable();
            }
        }

        private IEnumerable<UserProfile> GetUsersInOrdered(string orderedBy = "Username",
           IEnumerable<UserProfile> input = null)
        {
            if (input == null)
            {
                return null;
            }
            switch (orderedBy)
            {
                case "Email":
                    return input.OrderBy(profile => profile.Email);
                case "Fullname":
                    return input.OrderBy(profile => profile.FullName);
                case "Date":
                    return input.OrderBy(profile => profile.CreatedDate);
                case "Username_desc":
                    return input.OrderByDescending(profile => profile.UserName);
                case "Fullname_desc":
                    return input.OrderByDescending(profile => profile.FullName);
                case "Email_desc":
                    return input.OrderByDescending(profile => profile.Email);
                case "Date_desc":
                    return input.OrderByDescending(profile => profile.CreatedDate);
                default:
                    return input.OrderBy(profile => profile.UserName);
            }
        }
        #endregion
        
        // Get all users with no criterion
        public List<UserProfile> GetAllUsers()
        {
            return _userRepository.All.AsNoTracking().ToList();
        }

        // Get all users with PAGINATION and ORDERED BY UserProfile.UserId 
        public List<UserProfile> GetAllUsers(string ordered)
        {
            List<UserProfile> resultSet = this.QueryUsersInOrdered(ordered)
                            .ToList();
            return resultSet;
        }

        // Get all users with PAGINATION and ORDERED BY userId and FILTERED BY Role.RoleName
        public List<UserProfile> GetAllUsers(string roleName, string ordered)
        {
            var role = CacheProvider.Get(roleName, ()=>_userRepository.FindRole(roleName));

            var resultSet = role != null ? 
                this.GetUsersInOrdered(ordered, role.UserProfiles)
                    .ToList() : null;

            if (resultSet == null)
            {
                resultSet = GetAllUsers(ordered);
            }
            return resultSet;
        }

        // Get all users with PAGINATION and ORDERED BY userId and SEARCHED by an inputed search string
        public List<UserProfile> SearchUsers(string searchText, string ordered)
        {
            List<UserProfile> resultSet = CacheProvider.Get("DefaultQueryUsersInOrdered", ()=> this.QueryUsersInOrdered(ordered))
                             .Where(p => String.Concat(p.UserName, p.FullName, p.Email, p.City).Contains(searchText))
                             .ToList();
            return resultSet;
        }

        // Delete a group of Users
        public void MarkDeletedUsers(IEnumerable<int> ids)
        {
            foreach (var id in ids)
            {
                _userRepository.Delete(id);
            }
            _userRepository.Save();
        }

        // Undo delete a group of Users
        public void UnmarkDeletedUsers(IEnumerable<int> ids)
        {
            foreach (var id in ids)
            {
                var user = _userRepository.Find(id);
                user.IsDeleted = false;
                user.LastModified = DateTime.UtcNow;
                _userRepository.Update(user);
            }
            _userRepository.Save();
        }
    
        // Get a User 
        public UserProfile GetUser(int id)
        {
            return _userRepository.Find(id);
        }

        // Update a User
        public bool UpdateUser(UserProfile user)
        {
            try
            {
                _userRepository.Update(user);
                _userRepository.Save();
                return true;
            }
            catch (Exception)
            {
                throw;
            }
        }
    }
}
